package org.gap.jseed.contract;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.gap.jseed.contract.annotation.Condition;
import org.gap.jseed.contract.annotation.Ensure;
import org.gap.jseed.injection.ClassWriter;

public class EnsureValidation extends ValidationWriter {
	private static final String OLD = "old:";
	
	@Override
	public void injectBehavior(ClassWriter javaWriter, Method method, Annotation annotation) {
		Ensure pre = (Ensure) annotation;
		StringBuffer preConditions = new StringBuffer();
		StringBuffer postConditions = new StringBuffer();
		for (Condition each : pre.value()) {
			if (containsPreState(each)) {
				PreAndPostStateValidation extractor = new PreAndPostStateValidation(each);
				String preCondition = extractor.preCondition;
				String postCondition = extractor.postCondition;
				
				preConditions.append(preCondition);
				postConditions.append(postCondition);
			} else {
				String postCondition = createTestCondition(each.value()) + createPostConditionViolationException(each);
				postConditions.append(postCondition);
			}
		}
		if (preConditions.length() > 0) {
			javaWriter.insertBefore(method, preConditions.toString());
		}
		javaWriter.insertAfter(method, postConditions.toString());
	}

	private boolean containsPreState(Condition each) {
		return (each.value()).contains(OLD);
	}

	public class PreAndPostStateValidation {
		final String variableName = "result" + System.currentTimeMillis();
		String preCondition;
		String postCondition;
		
		public PreAndPostStateValidation(Condition condition) {
			String test = " " + condition.value() + " ";
			int start = test.indexOf(OLD);
			int end = start + OLD.length();
			for (; end < test.length(); end++) {
				if (test.charAt(end) == '=') {
					end--;
					break;
				}
			}
			String extractedPreAnnotation  = test.substring(start, end);
				
			String oldValueType = extractedPreAnnotation.split(":")[1];
			int whereTypeEnds = oldValueType.indexOf(' ');
			preCondition = "/* pre */" + oldValueType.substring(0, whereTypeEnds) + " " + variableName + " = " + oldValueType.trim().substring(whereTypeEnds) + ";";
			postCondition = "/* post */" + test.replace(extractedPreAnnotation , variableName);
			postCondition = EnsureValidation.this.createTestCondition(postCondition) + EnsureValidation.this.createPostConditionViolationException(condition);
		}
	}
}
